package com.libbase.utils

import android.annotation.SuppressLint
import android.app.Application
import android.content.Context
import android.os.Build
import android.os.Process
import android.text.TextUtils
import androidx.annotation.RequiresApi
import java.io.BufferedReader
import java.io.FileInputStream
import java.io.IOException
import java.io.InputStreamReader

class ProcessUtils {
    companion object {
        private var currentProcessName: String? = null

        @JvmStatic
        fun getCurrentProcessName(context: Context, hasAgreeUserPrivacy: Boolean): String? {
            if (!TextUtils.isEmpty(currentProcessName)) {
                return currentProcessName
            }

            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
                currentProcessName = getCurrentProcessNameByApplication()
            }
            if (!TextUtils.isEmpty(currentProcessName)) {
                return currentProcessName
            }

            currentProcessName = getCurrentProcessNameByActivityThread()
            if (!TextUtils.isEmpty(currentProcessName)) {
                return currentProcessName
            }

            if (hasAgreeUserPrivacy) {
                currentProcessName = getCurrentProcessNameByActivityManager(context)
                if (!TextUtils.isEmpty(currentProcessName)) {
                    return currentProcessName
                }
            }

            currentProcessName = getCurrentProcessNameByProcFile()

            return currentProcessName
        }

        @RequiresApi(Build.VERSION_CODES.P)
        private fun getCurrentProcessNameByApplication(): String? {
            return Application.getProcessName()
        }

        @SuppressLint("PrivateApi", "DiscouragedPrivateApi")
        private fun getCurrentProcessNameByActivityThread(): String? {
            var processName: String? = null
            try {
                val activityThreadClass = Class.forName("android.app.ActivityThread")
                val method = activityThreadClass.getDeclaredMethod("currentProcessName")
                method.isAccessible = true
                val result = method.invoke(null)
                if (result is String) {
                    processName = result
                }
            } catch (e: Throwable) {
                e.printStackTrace()
            }
            return processName
        }

        private fun getCurrentProcessNameByActivityManager(context: Context): String? {
            try {
                val activityManager =
                    context.getSystemService(Context.ACTIVITY_SERVICE) as android.app.ActivityManager
                for (processInfo in activityManager.runningAppProcesses) {
                    if (processInfo.pid == Process.myPid()) {
                        return processInfo.processName
                    }
                }
            } catch (e: Throwable) {
                e.printStackTrace()
            }
            return null
        }

        private fun getCurrentProcessNameByProcFile(): String? {
            var cmdlineReader: BufferedReader? = null
            try {
                cmdlineReader = BufferedReader(
                    InputStreamReader(
                        FileInputStream("/proc/" + Process.myPid() + "/cmdline"),
                        "iso-8859-1"
                    )
                )
                var c: Int
                val processName = StringBuilder()
                while (cmdlineReader.read().also { c = it } > 0) {
                    processName.append(c.toChar())
                }
                return processName.toString()
            } catch (e: Throwable) {
                e.printStackTrace()
            } finally {
                try {
                    cmdlineReader?.close()
                } catch (e: IOException) {
                    e.printStackTrace()
                }
            }
            return null
        }
    }
}